package com.wyh.service.serviceImpl.g3serviceimpl;

import com.wyh.common.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.wyh.service.g3service.*;
import com.wyh.domain.po.g3po.*;
import com.wyh.mapper.g3mapper.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BillingServiceImpl implements BillingService {

    @Autowired
    private G3ChargingMapper chargingMapper;

    @Autowired
    private G3BillMapper billMapper;

    @Autowired
    private G3ContractMapper contractMapper;

    @Autowired
    private G3CustomerMapper customerMapper;

    @Autowired
    private PrestorageService prestorageService;

    @Autowired
    private DifferentialAccountMapper differentialAccountMapper;

    @Autowired
    private BillDetailsService billDetailsService;

    @Autowired
    private G3BillingItemsMapper billingItemsMapper;


    @Autowired
    private ThreeMeterReadingMapper threeMeterReadingMapper;

    /**
     * 手动入账
     */
    @Override
    @Transactional
    public Result manualBilling(List<Integer> recordIds) {
        Result result = new Result();
        List<Integer> notFoundIds = new ArrayList<>();
        List<Integer> failedIds = new ArrayList<>();

        logInfo("接收到的记录ID: " + recordIds);

        for (Integer recordId : recordIds) {
            try {
                logInfo("处理记录ID: " + recordId);
                Charging charging = chargingMapper.findById(recordId);
                if (charging != null) {
                    logInfo("找到记录ID: " + recordId);
                    if (charging.getState() == 1) {
                        logInfo("记录ID: " + recordId + " 的状态为1，不可入账");
                        failedIds.add(recordId);
                        continue;
                    }
                    G3Bill bill = createBillWithDetails(charging); // 创建账单
                    logInfo("创建账单成功，账单ID: " + bill.getId());
                    int billDetailsId = createBillDetails(bill, charging); // 创建账单详情
                    logInfo("创建账单详情成功，账单详情ID: " + billDetailsId);

                    // 预存抵扣处理
                    handlePrestorageDeduction(billDetailsId, bill, charging.getResourceid(), charging.getUnitpriceid(), charging.getReceivable().doubleValue());
                    logInfo("预存抵扣处理完成");

                    charging.setState(1); // 设置状态为已入账
                    chargingMapper.updateChargingState(charging); // 更新收费记录的状态
                    logInfo("更新收费记录状态成功，记录ID: " + recordId);
                } else {
                    notFoundIds.add(recordId);
                    logInfo("未找到记录ID: " + recordId);
                }
            } catch (Exception e) {
                failedIds.add(recordId);
                logError("处理失败的记录ID: " + recordId, e);
            }
        }

        result.setMsg(generateManualBillingResultMessage(notFoundIds, failedIds));

        // 将notFoundIds、failedIds和成功的ID放入result的data中
        Map<String, Object> data = new HashMap<>();
        data.put("notFoundIds", notFoundIds);
        data.put("failedIds", failedIds);
        data.put("successIds", recordIds.stream()
                .filter(id -> !notFoundIds.contains(id) && !failedIds.contains(id))
                .collect(Collectors.toList()));
        result.setData(data);

        return result;
    }

    /**
     * 按合同入账
     */
    @Override
    @Transactional
    public Result billingByContract(List<Integer> recordIds) {
        Result result = new Result();
        List<Integer> notFoundIds = new ArrayList<>();
        List<Integer> failedIds = new ArrayList<>();

        logInfo("接收到的记录ID: " + recordIds);

        Map<Integer, List<Charging>> contractChargingMap = new HashMap<>();

        for (Integer recordId : recordIds) {
            try {
                Charging charging = chargingMapper.findById(recordId);
                if (charging != null) {
                    logInfo("找到记录ID: " + recordId);
                    if (charging.getState() == 1) {
                        logInfo("记录ID: " + recordId + " 的状态为1，不可入账");
                        failedIds.add(recordId);
                        continue;
                    }
                    G3Contract contract = contractMapper.getContractById(charging.getContractid());
                    if (contract == null) {
                        notFoundIds.add(recordId);
                        logInfo("未找到合同ID: " + charging.getContractid());
                        continue;
                    }

                    // 根据合同ID分组收费记录
                    contractChargingMap.computeIfAbsent(charging.getContractid(), k -> new ArrayList<>()).add(charging);
                    logInfo("记录ID: " + recordId + " 添加到合同ID: " + charging.getContractid() + " 的分组中");
                } else {
                    notFoundIds.add(recordId);
                    logInfo("未找到记录ID: " + recordId);
                }
            } catch (Exception e) {
                failedIds.add(recordId);
                logError("处理失败的记录ID: " + recordId, e);
            }
        }

        for (Map.Entry<Integer, List<Charging>> entry : contractChargingMap.entrySet()) {
            try {
                logInfo("开始处理合同ID: " + entry.getKey());
                createBillForContract(entry.getValue()); // 为每个合同创建账单
                logInfo("处理完成的合同ID: " + entry.getKey());
            } catch (Exception e) {
                failedIds.addAll(entry.getValue().stream().map(c -> c.getId()).collect(Collectors.toList()));
                logError("处理失败的合同ID: " + entry.getKey(), e);
            }
        }

        result.setMsg(generateContractBillingResultMessage(notFoundIds, failedIds));

        // 将notFoundIds、failedIds和成功的ID放入result的data中
        Map<String, Object> data = new HashMap<>();
        data.put("notFoundIds", notFoundIds);
        data.put("failedIds", failedIds);
        data.put("successIds", recordIds.stream()
                .filter(id -> !notFoundIds.contains(id) && !failedIds.contains(id))
                .collect(Collectors.toList()));
        result.setData(data);

        return result;
    }

    /**
     * 按合同批量入账
     */
    @Override
    @Transactional
    public Result billingAllByContract() {
        Result result = new Result();
        List<Integer> notFoundIds = new ArrayList<>();
        List<Integer> failedIds = new ArrayList<>();

        logInfo("获取所有未入账记录");

        List<Charging> allUnbilledChargings = chargingMapper.findAllUnbilled();
        Map<Integer, List<Charging>> contractChargingMap = new HashMap<>();

        for (Charging charging : allUnbilledChargings) {
            try {
                if (charging.getState() == 1) {
                    logInfo("记录ID: " + charging.getId() + " 的状态为1，不可入账");
                    failedIds.add(charging.getId());
                    continue;
                }
                G3Contract contract = contractMapper.getContractById(charging.getContractid());
                if (contract == null) {
                    notFoundIds.add(charging.getId());
                    logInfo("未找到合同ID: " + charging.getContractid());
                    continue;
                }

                // 根据合同ID分组收费记录
                contractChargingMap.computeIfAbsent(charging.getContractid(), k -> new ArrayList<>()).add(charging);
                logInfo("记录ID: " + charging.getId() + " 添加到合同ID: " + charging.getContractid() + " 的分组中");
            } catch (Exception e) {
                failedIds.add(charging.getId());
                logError("处理失败的记录ID: " + charging.getId(), e);
            }
        }

        for (Map.Entry<Integer, List<Charging>> entry : contractChargingMap.entrySet()) {
            try {
                logInfo("开始处理合同ID: " + entry.getKey());
                createBillForContract(entry.getValue()); // 为每个合同创建账单
                logInfo("处理完成的合同ID: " + entry.getKey());
            } catch (Exception e) {
                failedIds.addAll(entry.getValue().stream().map(c -> c.getId()).collect(Collectors.toList()));
                logError("处理失败的合同ID: " + entry.getKey(), e);
            }
        }

        result.setMsg(generateContractBillingResultMessage(notFoundIds, failedIds));

        // 将notFoundIds、failedIds和成功的ID放入result的data中
        Map<String, Object> data = new HashMap<>();
        data.put("notFoundIds", notFoundIds);
        data.put("failedIds", failedIds);
        data.put("successIds", allUnbilledChargings.stream()
                .map(Charging::getId)
                .filter(id -> !notFoundIds.contains(id) && !failedIds.contains(id))
                .collect(Collectors.toList()));
        result.setData(data);

        return result;
    }

    /**
     * 为指定合同创建账单
     */
    private void createBillForContract(List<Charging> chargings) {
        if (chargings.isEmpty()) {return;}

        Charging firstCharging = chargings.get(0);
        G3Contract contract = contractMapper.getContractById(firstCharging.getContractid());

        if (contract.getMerge() == 1) {
            // 按客户和物业名称分组收费记录
            Map<String, List<Charging>> groupedByCustomerAndProperty = chargings.stream().collect(Collectors.groupingBy(
                    c -> c.getCustomerid() + "-" + c.getPropertyname()
            ));

            for (List<Charging> group : groupedByCustomerAndProperty.values()) {
                logInfo("开始处理客户ID: " + group.get(0).getCustomerid() + " 和物业名称: " + group.get(0).getPropertyname());
                G3Bill bill = createBillWithDetailsForContract(group, contract); // 创建账单
                logInfo("创建账单成功，账单ID: " + bill.getId());
                for (Charging charging : group) {
                    int billDetailsId = createBillDetails(bill, charging); // 创建账单详情
                    logInfo("创建账单详情成功，账单详情ID: " + billDetailsId);

                    // 预存抵扣处理
                    handlePrestorageDeduction(billDetailsId, bill, charging.getResourceid(), charging.getUnitpriceid(), charging.getReceivable().doubleValue());
                    logInfo("预存抵扣处理完成");

                    charging.setState(1); // 设置状态为已入账
                    chargingMapper.updateChargingState(charging); // 更新收费记录的状态
                    logInfo("更新收费记录状态成功，记录ID: " + charging.getId());
                }
            }
        } else {
            G3Bill bill = createBillWithDetailsForContract(chargings, contract); // 创建账单
            logInfo("创建账单成功，账单ID: " + bill.getId());
            for (Charging charging : chargings) {
                int billDetailsId = createBillDetails(bill, charging); // 创建账单详情
                logInfo("创建账单详情成功，账单详情ID: " + billDetailsId);

                // 预存抵扣处理
                handlePrestorageDeduction(billDetailsId, bill, charging.getResourceid(), charging.getUnitpriceid(), charging.getReceivable().doubleValue());
                logInfo("预存抵扣处理完成");

                charging.setState(1); // 设置状态为已入账
                chargingMapper.updateChargingState(charging); // 更新收费记录的状态
                logInfo("更新收费记录状态成功，记录ID: " + charging.getId());
            }
        }
    }

    /**
     * 根据合同创建账单及详情
     */
    private G3Bill createBillWithDetailsForContract(List<Charging> chargings, G3Contract contract) {
        String customerName = customerMapper.findCustomerNameById(chargings.get(0).getCustomerid());
        ThreeMeterReading threeMeterReading =threeMeterReadingMapper.findThreeMeterReadingByContractId(contract.getId());

        G3Bill bill = new G3Bill();
        bill.setPayee(null); // 收款方
        bill.setBillnumber(null);
        bill.setNotificationstatus(0);
        bill.setArrearsstatus(0);
        bill.setAccounttime(threeMeterReading.getTime()); // 三表帐期（待改） threemeterreading的time
        bill.setReceivable(chargings.stream().mapToDouble(c -> c.getReceivable().doubleValue()).sum()); // 应收金额
        bill.setArrears(bill.getReceivable()); // 欠款金额
        bill.setState(0);
        bill.setCollectionstatus(0);
        bill.setPropertyname(chargings.get(0).getPropertyname());
        bill.setCustomername(customerName);
        bill.setCustomerid(chargings.get(0).getCustomerid());
        bill.setLaggold(0.0); // 滞纳金
        bill.setTotalarrears(bill.getLaggold() + bill.getArrears()); // 总欠款金额

        billMapper.insertBill(bill); // 插入账单记录

        return bill;
    }

    /**
     * 根据收费记录创建账单及详情
     */
    private G3Bill createBillWithDetails(Charging charging) {
        String customerName = customerMapper.findCustomerNameById(charging.getCustomerid());
        ThreeMeterReading threeMeterReading =threeMeterReadingMapper.findThreeMeterReadingByContractId(charging.getContractid());

        G3Bill bill = new G3Bill();
        bill.setPayee(null); // 收款方
        bill.setBillnumber(null);
        bill.setNotificationstatus(0);
        bill.setArrearsstatus(0);
        bill.setAccounttime(threeMeterReading.getTime()); // 三表账期（待改） thereemeterreading的time
        bill.setReceivable(charging.getReceivable() != null ? charging.getReceivable().doubleValue() : 0.0); // 应收金额
        bill.setArrears(0); // 欠款金额（待改）预存处理后的应付金额
        bill.setState(0);
        bill.setCollectionstatus(0);
        bill.setPropertyname(charging.getPropertyname());
        bill.setCustomername(customerName);
        bill.setCustomerid(charging.getCustomerid());
        bill.setLaggold(0.0); // 滞纳金
        bill.setTotalarrears(bill.getLaggold() + bill.getArrears()); // 总欠款金额

        billMapper.insertBill(bill); // 插入账单记录

        return bill;
    }

    /**
     * 创建账单详情
     */
    private int createBillDetails(G3Bill bill, Charging charging) {
        ThreeMeterReading threeMeterReading =threeMeterReadingMapper.findThreeMeterReadingByContractId(charging.getContractid());
        BillDetails billDetails = new BillDetails();

        billDetails.setBillid(bill.getId());
        billDetails.setBillingresources(charging.getResourcename());
        billDetails.setBillingresourcesid(String.valueOf(charging.getResourceid()));
        billDetails.setBillingitems(charging.getBillingitemsname());
        billDetails.setBillingitemsid(String.valueOf(charging.getUnitpriceid()));
        billDetails.setBillingnature(String.valueOf(charging.getBillingnature()));
        billDetails.setBillingnatureid(null);//计费性质id（待加） billitems中对应的id
        billDetails.setArea(String.valueOf(charging.getArea()));
        billDetails.setPrice(charging.getPrice());
        billDetails.setPreviousreading(String.valueOf( threeMeterReading.getPreviousreading()));//三表读数（待加）threemeterreading的previousreading
        billDetails.setCurrentreading(String.valueOf( threeMeterReading.getReading()));//三表读数（待加）threemeterreading的reading
        billDetails.setDosage(charging.getDosage());
        billDetails.setFrombilling(charging.getStarttime());
        billDetails.setEndofbilling(charging.getEndtime());
        billDetails.setAccountsreceivable(charging.getReceivable());//应收
        billDetails.setRefunddeduction(BigDecimal.ZERO);//退费抵扣（没加）
        billDetails.setPredepositoffset(null); //预存冲抵（待加）differentaccount的changeamout  注意对应
        billDetails.setVerificationamount(BigDecimal.ZERO);//核销金额（没加）
        billDetails.setDetailid(String.valueOf(charging.getBillid()));
        billDetails.setRemarks(charging.getRemarks());

        billDetailsService.insertBillDetails(billDetails); // 插入账单详情记录

        return billDetails.getId(); // 返回插入后的账单详情的ID
    }

    /**
     * 预存冲抵
     */
    private void handlePrestorageDeduction(int billDetailsId, G3Bill bill, int resourceId, int unitPriceId, double receivable) {
        double remainingReceivable = receivable;
        double totalSpecificDeduction = 0.0;
        double totalGeneralDeduction = 0.0;

        logInfo("开始处理预存抵扣，账单详情ID: " + billDetailsId + ", 资源ID: " + resourceId + ", 费项ID: " + unitPriceId + ", 应收金额: " + receivable);

        // 获取BillingItems对象，查询specialname
        BillingItems billingItems = billingItemsMapper.findById(unitPriceId);
        if (billingItems == null) {
            throw new IllegalArgumentException("未找到费项ID: " + unitPriceId + " 对应的BillingItems记录");
        }
        String specialname = String.valueOf(billingItems.getSpecialName());
        logInfo("获取到的specialname: " + specialname);

        try {
            // 查询专项预存
            List<G3Prestorage> specificPrestorages = prestorageService.findSpecificPrestorage(resourceId);
            logInfo("查询到的专项预存记录数有: " + specificPrestorages.size());

            for (G3Prestorage prestorage : specificPrestorages) {
                if (remainingReceivable <= 0) {
                    break;
                }

                // 检查Prestorage的subject
                logInfo("检查专项预存，prestorage的subject: " + prestorage.getSubject() + ", afterchange: " + prestorage.getAfterchange());
                int subject = prestorage.getSubject();
                if (subject >= 0 && subject <= 3 && specialname.equals(String.valueOf(subject))) {
                    double deductionAmount = Math.min(prestorage.getAfterchange(), remainingReceivable);
                    logInfo("处理专项预存冲抵，预存ID: " + prestorage.getId() + ", 抵扣金额: " + deductionAmount);

                    // 更新prestorage的beforechange值为当前afterchange值
                    prestorage.setBeforechange(prestorage.getAfterchange());
                    // 将抵扣后的金额存入afterchange
                    prestorage.setAfterchange(prestorage.getAfterchange() - deductionAmount);
                    // 将抵扣金额存入changeamount
                    prestorage.setChangeamount(deductionAmount);

                    prestorageService.updatePrestorage(prestorage); // 更新prestorage记录
                    remainingReceivable -= deductionAmount;
                    totalSpecificDeduction += deductionAmount;

                    logInfo("专项预存冲抵完成，剩余应收金额: " + remainingReceivable + ", 更新后的afterchange: " + prestorage.getAfterchange());
                }
            }

            // 查询通用预存
            if (remainingReceivable > 0) {
                List<G3Prestorage> generalPrestorages = prestorageService.findGeneralPrestorage(resourceId);
                logInfo("查询到的通用预存记录数: " + generalPrestorages.size());

                for (G3Prestorage prestorage : generalPrestorages) {
                    if (remainingReceivable <= 0) {
                        break;
                    }

                    // 检查Prestorage的subject
                    logInfo("检查通用预存，prestorage的subject: " + prestorage.getSubject() + ", afterchange: " + prestorage.getAfterchange());
                    if (prestorage.getSubject() == 4) {
                        double deductionAmount = Math.min(prestorage.getAfterchange(), remainingReceivable);
                        logInfo("处理通用预存冲抵，预存ID: " + prestorage.getId() + ", 抵扣金额: " + deductionAmount);

                        // 更新prestorage的beforechange值为当前afterchange值
                        prestorage.setBeforechange(prestorage.getAfterchange());
                        // 将抵扣后的金额存入afterchange
                        prestorage.setAfterchange(prestorage.getAfterchange() - deductionAmount);
                        // 将抵扣金额存入changeamount
                        prestorage.setChangeamount(deductionAmount);

                        prestorageService.updatePrestorage(prestorage); // 更新prestorage记录
                        remainingReceivable -= deductionAmount;
                        totalGeneralDeduction += deductionAmount;

                        logInfo("通用预存冲抵完成，剩余应收金额: " + remainingReceivable + ", 更新后的afterchange: " + prestorage.getAfterchange());
                    }
                }
            }

            // 更新账单的欠款金额
            bill.setArrears(remainingReceivable);
            billMapper.updateBill(bill);

            // 更新账单详情的预存冲抵金额
            BillDetails billDetails = billDetailsService.findById(billDetailsId);
            billDetails.setPredepositoffset(BigDecimal.valueOf(totalSpecificDeduction + totalGeneralDeduction));
            billDetailsService.updateBillDetails(billDetails);

            // 创建差异账户记录
            createDifferentialAccount(billDetailsId, resourceId, totalSpecificDeduction, totalGeneralDeduction, "预存冲抵", String.valueOf(unitPriceId));

            logInfo("预存抵扣处理完成，剩余应收金额: " + remainingReceivable);

        } catch (Exception e) {
            logError("预存抵扣处理失败", e);
            throw e; // 或者处理异常
        }
    }



    /**
     * 创建差异账户记录
     */
    private void createDifferentialAccount(int billDetailsId, int resourceId, double specificDeduction, double generalDeduction, String billingItemName, String subject) {
        DifferentialAccount differentialAccount = new DifferentialAccount();

        differentialAccount.setCustomerid(resourceId);
        differentialAccount.setType(Integer.parseInt(subject));
        differentialAccount.setPrice(BigDecimal.valueOf(specificDeduction + generalDeduction));
        differentialAccount.setRemarks(null);
        differentialAccount.setSpecificDeduction(BigDecimal.valueOf(specificDeduction));
        differentialAccount.setGeneralDeduction(BigDecimal.valueOf(generalDeduction));
        differentialAccount.setBilldetailsid(billDetailsId);

        differentialAccountMapper.insertDifferentialAccount(differentialAccount); // 插入差异账户记录
        logInfo("创建差异账户记录成功，差异账户ID: " + differentialAccount.getId());
    }


    /**
     * 打印日志信息
     */
    private void logInfo(String message) {
        System.out.println(message);
    }

    /**
     * 打印错误信息
     */
    private void logError(String message, Exception e) {
        System.out.println(message + ", 错误: " + e.getMessage());
        e.printStackTrace();
    }

    /**
     * 生成手动入账结果信息
     */
    private String generateManualBillingResultMessage(List<Integer> notFoundIds, List<Integer> failedIds) {
        StringBuilder message = new StringBuilder();
        if (notFoundIds.isEmpty() && failedIds.isEmpty()) {
            message.append("手动入账成功！");
        } else {
            message.append("手动入账部分成功。");
            if (!notFoundIds.isEmpty()) {
                message.append(" 以下ID未找到: ").append(notFoundIds.stream().map(String::valueOf).collect(Collectors.joining(", "))).append(".");
            }
            if (!failedIds.isEmpty()) {
                message.append(" 以下ID处理失败: ").append(failedIds.stream().map(String::valueOf).collect(Collectors.joining(", "))).append(".");
            }
        }
        return message.toString();
    }

    /**
     * 生成按合同入账结果信息
     */
    private String generateContractBillingResultMessage(List<Integer> notFoundIds, List<Integer> failedIds) {
        StringBuilder message = new StringBuilder();
        if (notFoundIds.isEmpty() && failedIds.isEmpty()) {
            message.append("按合同入账成功！");
        } else {
            message.append("按合同入账部分成功。");
            if (!notFoundIds.isEmpty()) {
                message.append(" 以下ID未找到: ").append(notFoundIds.stream().map(String::valueOf).collect(Collectors.joining(", "))).append(".");
            }
            if (!failedIds.isEmpty()) {
                message.append(" 以下ID处理失败: ").append(failedIds.stream().map(String::valueOf).collect(Collectors.joining(", "))).append(".");
            }
        }
        return message.toString();
    }
}
